using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Collections;
using Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.Mappings.Helper;
using Microsoft.Practices.RepositoryFactory.SchemaDiscovery.ObjectModel.Base;
using Microsoft.Practices.RepositoryFactory.SchemaDiscovery;
using Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.Mappings;
using Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.NamingConventions;
using Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel;
using Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.Mappings.Enums;
using System.Configuration;

namespace Microsoft.Practices.RepositoryFactory.CustomPages.Helpers
{
    internal static class UIHelper
    {
        public static string Finder;

        #region Public Finders
        public static Entity FindEntity(ArrayList entities, string entityName)
        {
            foreach (Entity entity in entities)
            {
                if (entity.Name == entityName)
                {
                    return entity;
                }
            }

            return null;
        }

        public static object FindParameter(ListBox lstMappings, string parameterName)
        {
            foreach (object item in lstMappings.Items)
            {
                PropertyParameterMapping mapping = (PropertyParameterMapping)item;

                if (mapping.Parameter == parameterName)
                {
                    return item;
                }
            }

            return null;
        }

        public static object FindProperty(ListBox lstMappings, string propertyName)
        {
            foreach (object item in lstMappings.Items)
            {
                PropertyParameterMapping mapping = (PropertyParameterMapping)item;

                if (mapping.Property == propertyName)
                {
                    return item;
                }
            }

            return null;
        }

        public static StoredProcedure FindStoredProcedure(ComboBox cmbStoredProcedures, string spName)
        {
            foreach (object item in cmbStoredProcedures.Items)
            {
                StoredProcedure sp = (StoredProcedure)item;

                if (sp.Name == spName)
                {
                    return sp;
                }
            }

            return null;
        }

        public static Parameter FindStoredProcedureParameter(StoredProcedure sp, string parameterName)
        {
            return FindStoredProcedureParameter(sp.Parameters, ParameterDirection.Input, parameterName);
        }

        public static Parameter FindStoredProcedureParameter(List<Parameter> parameters, ParameterDirection direction, string parameterName)
        {
            foreach (Parameter parameter in parameters)
            {
                if (direction == ParameterDirection.ReturnValue)
                {
                    string parameterName1 = ParseParamName(NamingHelper.GetMapBetweenPropertyAndDbVariable(parameter.Name));
                    string parameterName2 = ParseParamName(parameterName);
                    if (string.Compare(parameterName1, parameterName2, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        return parameter;
                    }
                }
                else
                {
                    string parameterName1 = ParseParamName(NamingHelper.GetMapBetweenPropertyAndDbVariable(parameter.Name));
                    string parameterName2 = ParseParamName(parameterName);
                    if (string.Compare(parameterName1, parameterName2, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        return parameter;
                    }
                }
            }

            return null;
        }

        private static string ParseParamName(string originalParamName)
        {
            int indexOfFirstUnderscore = originalParamName.IndexOf('_');

            if (indexOfFirstUnderscore == -1)
                return originalParamName;

            return originalParamName.Substring(indexOfFirstUnderscore + 1);
        }

        public static bool FindByStoredProcedureName(StoredProcedure storedProcedure)
        {
            if (storedProcedure != null)
            {
                return (storedProcedure.Name == Finder);
            }
            else
            {
                return false;
            }
        }

        public static bool FindByStoredProcedureName(EntityStoredProcedureMapping mapping)
        {
            if (mapping != null)
            {
                return (mapping.Procedure == Finder);
            }
            else
            {
                return false;
            }
        }

        public static bool FindByOperationName(EntityStoredProcedureMapping mapping)
        {
            if (mapping != null)
            {
                return (mapping.OperationName == Finder);
            }
            else
            {
                return false;
            }
        }
        #endregion

        #region Public Implementation
        /// <summary>
        /// Get parameters from an existing <see cref="StoredProcedure"/>.
        /// </summary>
        /// <param name="connectionSettings"></param>
        /// <param name="sp"></param>
        /// <param name="parameterDirection"></param>
        /// <returns></returns>
        public static List<Parameter> GetParameters(ConnectionStringSettings connectionSettings, StoredProcedure sp, ParameterDirection parameterDirection)
        {
            List<Parameter> parameters = new List<Parameter>();

            if (parameterDirection == ParameterDirection.ReturnValue)
            {
                // return all parameters.  Whether a parameter is hidden in the UI is
                // determined in the UI code (presenter).
                List<Parameter> allParameters = new List<Parameter>();
                DbSchemaDiscoverer dbSchemaDiscovery = new DbSchemaDiscoverer(connectionSettings);
                allParameters = dbSchemaDiscovery.DiscoverSPResultSet(sp);
                return allParameters;
            }
            else
            {
                foreach (Parameter parameter in sp.Parameters)
                {
                    if (parameter.Direction == parameterDirection)
                    {
                        parameters.Add(parameter);
                    }
                }
            }

            return parameters;
        }

        /// <summary>
        /// Gets a list of stored procedures so that the user can select the desired procedure.  
        /// Procedure parameters are not included.
        /// </summary>
        /// <param name="connectionSettings"></param>
        /// <returns></returns>
        public static List<StoredProcedure> GetStoredProcedures(ConnectionStringSettings connectionSettings)
        {
            DbSchemaDiscoverer dbSchemaDiscovery = new DbSchemaDiscoverer(connectionSettings);
            List<StoredProcedure> storedProcedures = dbSchemaDiscovery.DiscoverStoredProcedures();

            return storedProcedures;
        }

        public static void FillStoredProceduresCombo(ComboBox cmbStoredProcedures, List<StoredProcedure> storedProcedures)
        {
            foreach (StoredProcedure storedProcedure in storedProcedures)
            {
                cmbStoredProcedures.Items.Add(storedProcedure);
            }

            if (cmbStoredProcedures.Items.Count > 0)
            {
                cmbStoredProcedures.SelectedIndex = 0;
            }
        }

        public static void FillEntitiesListBox(ListBox lstEntities, ArrayList entities)
        {
            lstEntities.Items.Clear();

            if (lstEntities.Items.Count == 0)
            {
                foreach (Entity entity in entities)
                {
                    lstEntities.Items.Add(entity);
                }
            }

            if (lstEntities.Items.Count > 0)
            {
                lstEntities.SelectedIndex = 0;
            }
        }

        public static void FillParametersListBox(ListBox lstParameters, List<Parameter> parameters)
        {
            foreach (Parameter parameter in parameters)
            {
                lstParameters.Items.Add(CloneParameter(parameter));
            }
        }

        public static Parameter CloneParameter(Parameter parameter)
        {
            Parameter clonedParameter = ClonerHelper.CloneParameter(parameter);

            return clonedParameter;
        }

        public static void FillParametersListBox(ListBox lstParameters, ListBox lstMappings, List<Parameter> parameters)
        {
            foreach (Parameter parameter in parameters)
            {
                Parameter clonedParameter = ClonerHelper.CloneParameter(parameter);

                if (parameter.Direction == ParameterDirection.ReturnValue)
                {
                    if (UIHelper.FindParameter(lstMappings, clonedParameter.Name) == null)
                    {
                        lstParameters.Items.Add(clonedParameter);
                    }
                }
                else
                {
                    if (UIHelper.FindParameter(lstMappings, clonedParameter.Name) == null)
                    {
                        lstParameters.Items.Add(clonedParameter);
                    }
                }
            }
        }

        public static void RemoveMappingItems(ListBox entities, ListBox parameters, CheckedListBox mappings)
        {
            ArrayList itemsToRemove = new ArrayList();

            foreach (object item in mappings.CheckedItems)
            {
                PropertyParameterMapping mapping = (PropertyParameterMapping)item;

                entities.Items.Add(mapping.Property);
                parameters.Items.Add(mapping.ParameterInstance);
                itemsToRemove.Add(item);
            }

            foreach (object item in itemsToRemove)
            {
                mappings.Items.Remove(item);
            }

            if (mappings.Items.Count > 0)
            {
                mappings.SelectedIndex = 0;
            }
        }
        #endregion

        /// <summary>
        /// Gets a stored procedure and its parameters.
        /// </summary>
        /// <param name="procedureName"></param>
        /// <param name="connectionStringSettings"></param>
        /// <returns></returns>
        public static StoredProcedure GetStoredProcedure(string procedureName, ConnectionStringSettings connectionStringSettings)
        {
            DbSchemaDiscoverer dbSchemaDiscovery = new DbSchemaDiscoverer(connectionStringSettings);
            List<StoredProcedure> storedProcedures = dbSchemaDiscovery.DiscoverStoredProcedures();
            StoredProcedure result;

            foreach (StoredProcedure procedure in storedProcedures)
            {
                if (string.Compare(procedure.Name, procedureName, true) == 0)
                {

                    result = procedure;
                    result.Parameters.AddRange(dbSchemaDiscovery.DiscoverSPResultSet(result));
                    return result;
                }
            }

            return null;
        }

        public static bool IsMappableFrom(Property property, Parameter parameter)
        {
            string propertyName = property.Name.ToLowerInvariant().Replace("_", "");
            string parameterName = parameter.Name.ToLowerInvariant().Replace("_", "");

            bool isMappable = false;

            // exact comparison of names (invariant)
            isMappable = (string.Compare(propertyName, parameterName, StringComparison.InvariantCultureIgnoreCase) == 0);
            if (isMappable == true) return true;

            // mappable if the property name is the ending of a parameter name
            isMappable = parameterName.EndsWith(propertyName, StringComparison.InvariantCultureIgnoreCase);
            return isMappable;
        }
    }
}
